package com.zhiwei.common.filter;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.zhiwei.common.config.SecurityContext;
import com.zhiwei.common.constant.ErrorEnum;
import com.zhiwei.common.constant.HttpConstants;
import com.zhiwei.common.constant.ResultResponseMsg;
import com.zhiwei.common.service.GatewayService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.GenericFilterBean;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;

/**
 * @author ZHIWEI.YANG
 * @time 2019/11/24 - 15:21
 * @decription 安全过滤器，用于权限校验
 *
 * 注意：网关端自带白名单和token验证，无需重复验证
 */
@Component
@Slf4j
@ConditionalOnExpression("!'${spring.application.name}'.equals('publish-gateway')")
public class SecurityFilter extends GenericFilterBean {

    @Autowired
    private GatewayService gatewayService;

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {

        HttpServletRequest httpServletRequest = (HttpServletRequest) request;
        String requestUri = httpServletRequest.getRequestURI();
        String requestIp = httpServletRequest.getRemoteAddr();

        //请求Token
        String requestToken = httpServletRequest.getHeader(HttpConstants.HEADER_TOKEN);
        String origin = httpServletRequest.getHeader(HttpConstants.HEADER_ORIGIN);
        log.info("客户端【{}:{}】访问URL:{},请求Token:{}, request ===> {}", requestIp, origin, requestUri
                , requestToken, JSON.toJSONString(httpServletRequest.getParameterMap()));

        if (isUrlWhiteList(requestUri)) {
            log.info("请求路径【{}】在白名单，无需验证Token", requestUri);
            chain.doFilter(request, response);
            return;
        }

        String username = isValidToken(requestToken);
        SecurityContext.setUsername(username);
        if (StringUtils.isEmpty(username)) {
            SecurityContext.clear();
            log.error("请求路径【{}:{}】Token校验失败，请使用正确Token访问", requestUri, requestToken);
            ResultResponseMsg resultResponseMsg = ResultResponseMsg.buildResultMsg(ErrorEnum.HTTP_TOKEN, null);
            response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
            response.getWriter().println(JSON.toJSONString(resultResponseMsg, SerializerFeature.WriteMapNullValue));
            response.getWriter().flush();
            response.getWriter().close();
            return;
        }
        chain.doFilter(request, response);
    }

    /**
     * 校验请求地址是否是白名单
     * @param requestUri
     * @return
     */
    private boolean isUrlWhiteList(String requestUri) {
        if (StringUtils.isEmpty(requestUri)) {
            return false;
        }
        return gatewayService.checkWhiteList(requestUri);
    }

    /**
     * 校验请求Token(服务网关校验)
     * @param token
     * @return
     */
    private String isValidToken(String token) {
        return gatewayService.checkToken(token);
    }
}
